﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Reflection;

namespace ChangeRCVersion
{
    class Program
    {
        public static string version = "7.3.8.20";

        static void Main(string[] args)
        {
            string currentDir = System.Environment.CurrentDirectory;
            ChangeExeVersion("a.exe", version, currentDir);
        }


        public static void ChangeExeVersion(string _exe, string _version, string _dir)
        {
            string tempRC = @"temp.rc";
            string tempRES = @"temp.res";

            #region Extract ResHacker & Rc.exe

            //string def = Path.Combine(Temp, "Dialogs.def");
            string reshacker = Path.Combine(_dir, "ResHacker.exe");
            string rc = Path.Combine(_dir, "RC.Exe");
            string rcdll = Path.Combine(_dir, "RcDll.Dll");

            //ExtractResource("WebDeploymentUtility.Dialogs.def", def);
            ExtractResource("ChangeRCVersion.ResHacker.exe", reshacker);
            ExtractResource("ChangeRCVersion.RC.Exe", rc);
            ExtractResource("ChangeRCVersion.RcDll.Dll", rcdll);

            #endregion

            #region Exstract .rc

            var arg = new StringBuilder();
            arg.Append("-extract");
            arg.Append(" ");
            arg.Append(QuoteString(_exe));
            arg.Append(",");
            arg.Append(QuoteString(tempRC));
            arg.Append(",");
            arg.Append("VERSIONINFO,,");

            var startInfo = new ProcessStartInfo(reshacker)
            {
                WorkingDirectory = _dir,
                Arguments = arg.ToString(),
                UseShellExecute = true
            };
            Process process = new Process { StartInfo = startInfo };

            process.Start();

            while (!process.HasExited) { }

            #endregion

            #region Change RC Version

            ChangeRC(tempRC, "1.0.0.0");

            #endregion

            #region Merge .RC to .RES

            arg = new StringBuilder();
            arg.Append("/n /v /fo");
            arg.Append(" ");
            arg.Append(QuoteString(tempRES));
            arg.Append(" ");
            arg.Append(QuoteString(tempRC));

            startInfo = new ProcessStartInfo(rc)
            {
                WorkingDirectory = _dir,
                Arguments = arg.ToString(),
                UseShellExecute = true
            };
            process = new Process { StartInfo = startInfo };

            process.Start();

            while (!process.HasExited) { }

            #endregion

            #region Overwrite Exe Resource

            arg = new StringBuilder();
            arg.Append("-addoverwrite");
            arg.Append(" ");
            arg.Append(QuoteString(_exe));
            arg.Append(",");
            arg.Append(QuoteString(_exe));
            arg.Append(",");
            arg.Append(QuoteString(tempRES));
            arg.Append(",,,");

            startInfo = new ProcessStartInfo(reshacker)
            {
                WorkingDirectory = _dir,
                Arguments = arg.ToString(),
                UseShellExecute = true
            };
            process = new Process { StartInfo = startInfo };

            process.Start();

            while (!process.HasExited) { }
            
            #endregion
        }

        public static string QuoteString(string str)
        {
            if (string.IsNullOrEmpty(str)) return str;

            return ("\"" + str + "\"");
        }
        
        public static void ExtractResource(string resourceName, string targetFile)
        {
            using (var res = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
            {
                if (res == null) return;

                using (var fs = new FileStream(targetFile, FileMode.Create, FileAccess.Write))
                {
                    using (var bw = new BinaryWriter(fs))
                    {
                        var buffer = new byte[1024];
                        int cbRead;
                        do
                        {
                            cbRead = res.Read(buffer, 0, 1024);
                            bw.Write(buffer, 0, cbRead);
                        } while (cbRead >= 1024);
                    }
                }
            }
        }

        public static void ChangeRC(string filename, string version)
        {
            StreamReader sr = new StreamReader(filename);
            string content = sr.ReadToEnd();
            sr.Close();

            Regex r = new Regex(version);
            MatchEvaluator me1 = new MatchEvaluator(ReplaceFileVer);
            MatchEvaluator me2 = new MatchEvaluator(ReplaceProVer);
            content = Regex.Replace(content, GetDotVersion(version), me1);
            content = Regex.Replace(content, version, me2);

            Console.WriteLine(content);
            Console.WriteLine("///////////////////////////////////////");

            FileStream fs = new FileStream(filename, FileMode.OpenOrCreate);
            StreamWriter sw = new StreamWriter(fs);
            sw.Write(content);
            sw.Flush();
            sw.Close();
            fs.Close();
        }

        public static string GetDotVersion(string ver)
        {
            StringBuilder sb = new StringBuilder(ver);
            return ver.Replace('.', ',');
        }

        public static string ReplaceFileVer(Match m)
        {
            return GetDotVersion(version);
        }

        public static string ReplaceProVer(Match m)
        {
            return version;
        }
    }
}
